/*
*   Copyright (c) 2011 CPE 453-UAH03 <https://code.google.com/p/uah03-qtaprs/>
*   This file is part of qt-aprs.
*
*   qt-aprs is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   qt-aprs is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include <qfile.h>
#include <cmath>
#include <QTextStream>
#include <iostream>
#include <QFileDialog>
#include "configerror.h"
#include "dbdialog.h"
#include "QTcpSocket"
#include "datahandler.h"
#include "beepintvalidator.h"
#include <iomanip>
#include <sstream>
#include "mapdialog.h"
#include <QtGui>
#include <notice.h>

DataHandler *dataHandler = new DataHandler();

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

    d = new MapDialog();
    //d->showMaximized();
    d->show();


    connections = new ConnectionInterface();

    ui->setupUi(this);

    connectionStatus = false;
    socket = new QTcpSocket;
    stream = new QTextStream(socket);
    aprs_parser = new APRSParser();
    icon = "";

    ui->clearBox->insertItem(0,"min");
    ui->clearBox->insertItem(1, "hrs");
    ui->clearBox->setCurrentIndex(1);
    ui->purgeBox->insertItem(0, "hrs");
    ui->purgeBox->insertItem(1, "days");
    ui->purgeBox->setCurrentIndex(1);

    //connect(ui->MapButton, SIGNAL(clicked()), this, SLOT(ShowMaps()));

    connect(ui->actionDatabase_Configuration, SIGNAL(triggered()), this, SLOT(DBConfig()));
    connect(ui->actionAbout_Us, SIGNAL(triggered()), this, SLOT(aboutUs()));
    connect(ui->actionLoad_Settings, SIGNAL(triggered()), this, SLOT(LoadSettings()));
    connect(ui->actionSave_Settings, SIGNAL(triggered()), this, SLOT(SaveSettings()));
    connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(onClose()));
    connect(ui->actionDisconnect_from_Server, SIGNAL(triggered()), this, SLOT(disconnect()));
    connect(ui->actionConnect_To_Server, SIGNAL(triggered()), this, SLOT(ShowMaps()));
    connect(ui->actionConfigure_Server_Connections, SIGNAL(triggered()), this, SLOT(configureConnections()));

    //connect(ui->SaveConfigButton, SIGNAL(clicked()), this, SLOT(SaveSettings()));
    //connect(ui->LoadConfigButton, SIGNAL(clicked()), this, SLOT(LoadSettings()));
    //connect(ui->dbButton, SIGNAL(clicked()), this, SLOT(DBConfig()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(ParseData()));
    connect(connections,SIGNAL(newData(QString)), this, SLOT(ParseData(QString)));
    //connect(ui->DisconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
    //connect(ui->CloseButton, SIGNAL(clicked()), this, SLOT(onClose()));
    connect(ui->IconButton, SIGNAL(clicked()), this, SLOT(selectIcon()));
    connect(ui->SendButton, SIGNAL(clicked()), this, SLOT(transmitReport()));
    //ui->DisconnectButton->setDisabled(true);
    ui->LatLE->setValidator(new BeepIntValidator(-90.999999999, 90.999999999, 9, this));
    ui->LongLE->setValidator(new BeepIntValidator(-180.999999999, 180.999999999, 9, this));
    connect(ui->SendButton, SIGNAL(clicked()),this,SLOT(createPositionReport()));
    connect(dataHandler, SIGNAL(StationPlot(QString,char,char,float,float)), this, SLOT(plotStation(QString,char,char,float,float)));
    connect(dataHandler, SIGNAL(StationClear(QString)), this, SLOT(clearStation(QString)));
    //connect(ui->ConfigureConnectionsPB, SIGNAL(clicked()), this, SLOT(configureConnections()));
    autoLoad();
}

void MainWindow::ShowMaps()
{
    if (ui->Callsign_LineEdit->text() == NULL || ui->UserName_lineEdit->text() == NULL ||
        ui->Password_lineEdit->text() == NULL || ui->ServerName_lineEdit->text() == NULL ||
        icon == NULL || ui->LatLE->text() == NULL || ui->LongLE->text() == NULL)
    {
        ConfigError *c = new ConfigError(this);
        c->show();
        qDebug() << "No configuration file specified";
    }
    else
    {

        QStringList serverInfo = ui->ServerName_lineEdit->text().split(":");

        QString RealServerName = serverInfo[0];

        QString temp = serverInfo[1];
        QString FILTER = "filter " + ui->Filter_Param_Line_Edit->text();

        qint32 PortNumber = temp.toInt();

        QString authname = "user " + ui->UserName_lineEdit->text().toAscii() + " pass " + ui->Password_lineEdit->text().toAscii() + " vers testsoftware v1  " + ui->Filter_Param_Line_Edit->text().toAscii() + "\n";

        if(connectionStatus == false)
        {
            socket->connectToHost(RealServerName, PortNumber, QAbstractSocket::ReadWrite);
            socket->waitForConnected(50000);
            this->connectionStatus = true;

            qDebug() << "Authentication String = " << authname.toAscii();
            socket->waitForConnected(50000);
            qDebug() << "Connection State = " << socket->state();
        }

        if(socket->state() == QAbstractSocket::ConnectedState)
        {
            QByteArray block = authname.toAscii();
            socket->write(block);
            //ui->MapButton->setText("Connected!");
            //ui->MapButton->setDisabled(true);
            //ui->DisconnectButton->setEnabled(true);
            ui->Callsign_LineEdit->setDisabled(true);
            ui->ClearTime_spinBox->setDisabled(true);
            ui->Comment_LineEdit->setDisabled(true);
            ui->ConfigFileName_lineEdit->setDisabled(true);
            ui->Filter_Param_Line_Edit->setDisabled(true);
            ui->Password_lineEdit->setDisabled(true);
            ui->LongLE->setDisabled(false);
            ui->LatLE->setDisabled(false);
            ui->PurgeTime_spinBox->setDisabled(true);
            ui->ServerName_lineEdit->setDisabled(true);
            ui->StationType_LineEdit->setDisabled(true);
            ui->UserName_lineEdit->setDisabled(true);
            //ui->LoadConfigButton->setDisabled(true);
            //ui->SaveConfigButton->setDisabled(true);
            //ui->CloseButton->setDisabled(true);
            //ui->dbButton->setDisabled(true);
            ui->IconButton->setDisabled(true);

            dataHandler->clearUnit = ui->clearBox->currentText();
            dataHandler->purgeUnit = ui->purgeBox->currentText();
            dataHandler->clearTime = ui->ClearTime_spinBox->value();
            dataHandler->purgeTime = ui->PurgeTime_spinBox->value();

            qreal x = ui->LongLE->text().toDouble();
            qreal y = ui->LatLE->text().toDouble();
            QPixmap User(icon);
            QPointF *UserLocation = new QPointF(x, y);
            QString callsign = ui->Callsign_LineEdit->text();

            d->plotUser(callsign, User, UserLocation);
        }
    }
}

void MainWindow::SaveSettings()
{
    QString filename = QFileDialog::getSaveFileName(this, tr("Save Settings"), "", tr("Settings File (*.txt)"));
   QFile f(filename);
    // QFile f(ui->ConfigFileName_lineEdit->text());
    if( f.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&f);
        stream << ui->Callsign_LineEdit->text() << endl;
        stream << ui->StationType_LineEdit->text() << endl;
        stream << ui->LatLE->text() << endl;
        stream << ui->LongLE->text() << endl;
        stream << ui->Comment_LineEdit->text() << endl;
        stream << ui->UserName_lineEdit->text() << endl;
        stream << ui->Password_lineEdit->text() << endl;
        stream << ui->ServerName_lineEdit->text() << endl;
        stream << ui->Filter_Param_Line_Edit->text() <<endl;
        stream << icon << endl;
        stream.flush();
        f.close();
    }
    else
        qDebug() << "Could not create file!";
}

void MainWindow::autoSave()
{
    QFile f("quicksave.as");
    if( f.open(QIODevice::WriteOnly))
    {
        QTextStream stream(&f);
        stream << ui->Callsign_LineEdit->text() << endl;
        stream << ui->StationType_LineEdit->text() << endl;
        stream << ui->LatLE->text() << endl;
        stream << ui->LongLE->text() << endl;
        stream << ui->Comment_LineEdit->text() << endl;
        stream << ui->UserName_lineEdit->text() << endl;
        stream << ui->Password_lineEdit->text() << endl;
        stream << ui->ServerName_lineEdit->text() << endl;
        stream << ui->Filter_Param_Line_Edit->text() <<endl;
        stream << icon << endl;

        QStringList servers = connections->getConnectionNames();
        stream << servers.size() << endl;

        for(int i = 0; i < servers.size(); i++)
        {
            stream << connections->getName(i) << endl;
            stream << connections->getHostName(i) << endl;
            stream << connections->getPortNumber(i) << endl;
            stream << connections->getUserName(i) << endl;
            stream << connections->getPassword(i) << endl;
            stream << connections->getFilterString(i) << endl;
            stream << connections->isTransmitEnabled(i) << endl;
            stream << connections->isConnected(i) << endl;
        }

        stream.flush();
        f.close();
    }
    else
        qDebug() << "Could not create file!";
}

void MainWindow::autoLoad()
{
    QFile f("quicksave.as");
    QString callsign, stationType, Latitude, Longitude, comment, username, password, serverName, filter;
    QString name, hostName, userName, filterString;
    int portNumber, loop;
    loop = 0;
    bool transmitEnabled, connected;

    if( f.open(QIODevice::ReadOnly))
    {
        QTextStream stream(&f);
        callsign = stream.readLine();
        stationType = stream.readLine();
        Latitude = stream.readLine();
        Longitude = stream.readLine();
        comment = stream.readLine();
        username = stream.readLine();
        password = stream.readLine();
        serverName = stream.readLine();
        filter = stream.readLine();
        icon = stream.readLine();
        loop = stream.readLine().toInt();

        for(int i = 0; i < loop; i++)
        {
            name = stream.readLine();
            hostName = stream.readLine();
            portNumber = stream.readLine().toInt();
            userName = stream.readLine();
            password = stream.readLine();
            filterString = stream.readLine();
            transmitEnabled = stream.readLine().toInt();
            connected = stream.readLine().toInt();

            if(transmitEnabled == 1)
                transmitEnabled = true;
            if(connected == 1)
                connected = true;
            connections->newConnection(name.toAscii(),hostName.toAscii(),portNumber,userName.toAscii(),password.toAscii(),filterString.toAscii(),transmitEnabled);

            qDebug() << name << " " << hostName << " " << userName << " " << password << " " << filterString << " " << endl;

            if(connected)
                connections->connectToServer(i);
        }


        stream.flush();
        f.close();

        ui->Callsign_LineEdit->setText(callsign);
        ui->StationType_LineEdit->setText(stationType);
        ui->LatLE->setText(Latitude);
        ui->LongLE->setText(Longitude);
        ui->Comment_LineEdit->setText(comment);
        ui->UserName_lineEdit->setText(username);
        ui->Password_lineEdit->setText(password);
        ui->ServerName_lineEdit->setText(serverName);
        ui->Filter_Param_Line_Edit->setText(filter);
    }
    else
        qDebug() << "Could not open file!";
}

void MainWindow::LoadSettings()
{
    QFileDialog q(this);

    q.setFileMode(QFileDialog::ExistingFile);
    q.setNameFilter(tr("ConfigFile (*.txt)"));
    q.setViewMode(QFileDialog::List);

    QStringList SelectedConfigFile;
    if(q.exec())
        SelectedConfigFile = q.selectedFiles();
    if(SelectedConfigFile.count() > 0)
    {
        QString filename = SelectedConfigFile[0];

        QString callsign, stationType, Latitude, Longitude, comment, username, password, serverName, filter;
        QFile f(filename);
        if( f.open(QIODevice::ReadOnly))
        {
            QTextStream stream(&f);
            callsign = stream.readLine();
            stationType = stream.readLine();
            Latitude = stream.readLine();
            Longitude = stream.readLine();
            comment = stream.readLine();
            username = stream.readLine();
            password = stream.readLine();
            serverName = stream.readLine();
            filter = stream.readLine();
            icon = stream.readLine();
            stream.flush();
            f.close();

            ui->Callsign_LineEdit->setText(callsign);
            ui->StationType_LineEdit->setText(stationType);
            ui->LatLE->setText(Latitude);
            ui->LongLE->setText(Longitude);
            ui->Comment_LineEdit->setText(comment);
            ui->UserName_lineEdit->setText(username);
            ui->Password_lineEdit->setText(password);
            ui->ServerName_lineEdit->setText(serverName);
            ui->ConfigFileName_lineEdit->setText(filename);
            ui->Filter_Param_Line_Edit->setText(filter);
        }
        else
            qDebug() << "Could not open file!";
    }
}

void MainWindow::ParseData()
{
    QString infoString = stream->readLine();
    dataHandler->StoreData(infoString);
}

void MainWindow::ParseData(QString data)
{
    dataHandler->StoreData(data);
}

void MainWindow::disconnect()
{
    stream->flush();
    socket->flush();
    socket->close();

    this->connectionStatus = false;

    //ui->MapButton->setText("Connect to server");
    //ui->MapButton->setEnabled(true);
    //ui->DisconnectButton->setDisabled(true);
    ui->Callsign_LineEdit->setEnabled(true);
    ui->ClearTime_spinBox->setEnabled(true);
    ui->Comment_LineEdit->setEnabled(true);
    ui->ConfigFileName_lineEdit->setEnabled(true);
    ui->Filter_Param_Line_Edit->setEnabled(true);
    ui->Password_lineEdit->setEnabled(true);
    ui->PurgeTime_spinBox->setEnabled(true);
    ui->ServerName_lineEdit->setEnabled(true);
    ui->StationType_LineEdit->setEnabled(true);
    ui->UserName_lineEdit->setEnabled(true);
    //ui->LoadConfigButton->setEnabled(true);
    //ui->SaveConfigButton->setEnabled(true);
    //ui->CloseButton->setEnabled(true);
    //ui->dbButton->setEnabled(true);
    ui->IconButton->setEnabled(true);
}

void MainWindow::DBConfig()
{
    if(ui->clearBox->currentText() == "hrs" && ui->purgeBox->currentText() == "hrs" && ui->PurgeTime_spinBox->value() < ui->ClearTime_spinBox->value())
    {
        QMessageBox::critical(0, qApp->tr("Ivalid Purge and Clear time"),	//Displays error if connection to database fails
            qApp->tr("Purge time cannot be less than Clear time.\n"
                     "Please fix these values and try again."), QMessageBox::Ok);
    }
    else
    {
        DBDialog *db = new DBDialog(this, dataHandler);
        dataHandler->clearUnit = ui->clearBox->currentText();
        dataHandler->purgeUnit = ui->purgeBox->currentText();
        dataHandler->clearTime = ui->ClearTime_spinBox->value();
        dataHandler->purgeTime = ui->PurgeTime_spinBox->value();
        db->show();
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onClose()
{
    autoSave();
    d->close();
    this->close();
}

void MainWindow::selectIcon()
{
    QFileDialog q(this);

    q.setFileMode(QFileDialog::ExistingFile);
    q.setNameFilter(tr("Icon (*.*)"));
    q.setViewMode(QFileDialog::Detail);

    QStringList Icon;

    if(q.exec())
        Icon = q.selectedFiles();

    if(Icon.count() > 0)
        icon = Icon[0];
}

void MainWindow::transmitReport()
{
    qreal x = ui->LongLE->text().toDouble();
    qreal y = ui->LatLE->text().toDouble();
    QPixmap User(icon);
    QPointF *UserLocation = new QPointF(x, y);
    QString callsign = ui->Callsign_LineEdit->text();

    d->plotUser(callsign, User, UserLocation);

    connections->writeToSocket(positionReport);
}

void MainWindow::clearStation(QString callsign)
{
    d->clearStation(callsign);
}

void MainWindow::createPositionReport()
{
    positionReport = "";
    double latitude = ui->LatLE->text().toDouble();
    double longitude = ui->LongLE->text().toDouble();
    QString type = ui->StationType_LineEdit->text();

    QChar lat,lon,primSec,symType;
    int LatDeg, LatMin, LatSec, LonDeg, LonMin, LonSec;

    primSec = type[0];
    symType = type[1];

    if(latitude > 0)
    {
        lat = 'N';
    }
    else
    {
        lat = 'S';
    }

    if(longitude > 0)
    {
        lon = 'E';
    }
    else
    {
        lon = 'W';
    }
    // Compute degrees, minutes and seconds
    LatDeg = (int)fabs(latitude);
    LatMin = ((fabs(latitude) - LatDeg) * 60);
    LatSec = ceil((((fabs(latitude) - LatDeg) * 60) - LatMin) * 60);

    LonDeg = (int)fabs(longitude);
    LonMin = ((fabs(longitude) - LonDeg) * 60);
    LonSec = ceil((((fabs(longitude) - LonDeg) * 60) - LonMin) * 60);

    positionReport.append(ui->Callsign_LineEdit->text());
    positionReport.append(">APRS:!");
    positionReport.append(intToString(LatDeg,3));
    positionReport.append(intToString(LatMin,2));
    positionReport.append(".");
    positionReport.append(intToString(LatSec,2));
    positionReport.append(lat);
    positionReport.append(primSec);
    positionReport.append(intToString(LonDeg,3));
    positionReport.append(intToString(LonMin,2));
    positionReport.append(".");
    positionReport.append(intToString(LonSec, 2));
    positionReport.append(lon);
    positionReport.append(symType);
    positionReport.append(ui->Comment_LineEdit->text());
    qDebug() << positionReport;
}

void MainWindow::plotStation(QString callsign, char symbolTable, char symbolCode, float lat, float lon)
{
    d->plotActualStation(callsign, symbolTable, symbolCode, lat, lon);
}

QString MainWindow::intToString(int num, int size)
{
    std::ostringstream ss;
    ss << std::setw( size ) << std::setfill( '0' ) << num;
    return QString::fromStdString(ss.str());
}

void MainWindow::configureConnections()
{
    _CS = new ConnectionSelector(this);
    _CS->setConnectionInteface(connections);
    _CS->show();
}

void MainWindow::aboutUs()
{
    notice *note = new notice();
    note->setWindowTitle("GPL Product License");
    note->show();
}
